using System;
using System.ComponentModel;
using System.IO;
using System.Text;
using RollManager.Library.Utils;

namespace RollManager.Library.ActionSteps
{
    [Serializable]
    public class CopyFilesStep : ActionStep
    {
        #region Properties
        private string[] m_excludeFiles = new string[ 0 ];
        private string[] m_excludeFolders = new string[ 0 ];
        private string m_destDir = StepConstants.PATH;
        private string m_filter = StepConstants.FILTER;
        private string m_srcDir = StepConstants.PATH;
        private bool m_mirror = true;
        private bool m_recursive = false;
        private bool m_removeReadonly = true;
        private bool m_verbose = false;
        private int m_numRetries = 1000000;
        private int m_waitTime = 30;

        [DisplayName( "Destination Dir" )]
        [Description( "The destination directory path to which files are copied." )]
        public string DestDir
        {
            get
            {
                return m_destDir;
            }
            set
            {
                if( string.IsNullOrEmpty( value ) )
                {
                    throw new ArgumentException( "Destination Dir cannot be empty." );
                }
                else
                {
                    m_destDir = value.Trim();
                }
            }
        }

        [DisplayName( "Exclude Directories" )]
        [Description( "Excludes directories matching given names/paths." )]
        public string[] ExcludeFolders
        {
            get
            {
                return m_excludeFolders;
            }
            set
            {
                m_excludeFolders = value;
            }
        }

        [DisplayName( "Exclude Files" )]
        [Description( "Excludes files matching given names, paths, or wildcard characters." )]
        public string[] ExcludeFiles
        {
            get
            {
                return m_excludeFiles;
            }
            set
            {
                m_excludeFiles = value;
            }
        }

        [DisplayName( "File Filter" )]
        [Description( "The file filter to use when copying files from the source to the destination." )]
        public string Filter
        {
            get
            {
                return m_filter;
            }
            set
            {
                if( string.IsNullOrEmpty( value ) )
                {
                    throw new ArgumentException( "Filter cannot be empty.  Use *.* for a global wildcard." );
                }
                else
                {
                    m_filter = value.Trim();
                }
            }
        }

        [Description( "Whether the destination files should be deleted that aren't in the source directory." )]
        public bool Mirror
        {
            get
            {
                return m_mirror;
            }
            set
            {
                m_mirror = value;
            }
        }

        [DisplayName( "Number of Retries" )]
        [Description( "Specifies the number of retries on failed copies." )]
        public int NumRetries
        {
            get
            {
                return m_numRetries;
            }
            set
            {
                m_numRetries = value;
            }
        }

        [DisplayName( "Remove Readonly" )]
        [Description( "Whether the destination files should be have the read only flag removed." )]
        public bool RemoveReadonly
        {
            get
            {
                return m_removeReadonly;
            }
            set
            {
                m_removeReadonly = value;
            }
        }

        [Description( "Whether the copy should only apply to the top level source directory or to all children directories as well." )]
        public bool Recursive
        {
            get
            {
                return m_recursive;
            }
            set
            {
                m_recursive = value;
            }
        }

        [DisplayName( "Source Dir" )]
        [Description( "The source directory path from where files are copied." )]
        public string SrcDir
        {
            get
            {
                return m_srcDir;
            }
            set
            {
                if( string.IsNullOrEmpty( value ) )
                {
                    throw new ArgumentException( "Source Dir cannot be empty." );
                }
                else
                {
                    m_srcDir = value.Trim();
                }
            }
        }

        [Description( "Whether the copy should produce verbose output, showing skipped files." )]
        public bool Verbose
        {
            get
            {
                return m_verbose;
            }
            set
            {
                m_verbose = value;
            }
        }

        [DisplayName( "Wait Time" )]
        [Description( "Specifies the wait time between retries in seconds." )]
        public int WaitTime
        {
            get
            {
                return m_waitTime;
            }
            set
            {
                m_waitTime = value;
            }
        }

        public override string Name
        {
            get { return "Copy Files"; }
        }
        #endregion

        protected override void Run()
        {
            Common.RunCommand( Command, Args, Progress );
        }

        private string Args
        {
            get
            {
                StringBuilder args = new StringBuilder();
                args.AppendFormat( @"""{0}"" ""{1}"" {2}", m_srcDir, m_destDir, m_filter );

                if( m_recursive )
                {
                    args.Append( " /S" );
                }
                if( m_mirror )
                {
                    args.Append( " /MIR" );
                }
                if( m_removeReadonly )
                {
                    args.Append( " /A-:R" );
                }
                if( m_verbose )
                {
                    args.Append( " /V" );
                }
                args.AppendFormat( " /R:{0}", m_numRetries );
                args.AppendFormat( " /W:{0}", m_waitTime );
                args.Append( " /NP" );

                if( m_excludeFiles != null && m_excludeFiles.Length > 0 )
                {
                    args.Append( " /XF" );
                    foreach( string file in m_excludeFiles )
                    {
                        args.AppendFormat( " \"{0}\"", file );
                    }
                }

                if( m_excludeFolders != null && m_excludeFolders.Length > 0 )
                {
                    args.Append( " /XD" );
                    foreach( string dir in m_excludeFolders )
                    {
                        args.AppendFormat( " \"{0}\"", dir );
                    }
                }

                return args.ToString();
            }
        }

        private string Command
        {
            get { return Path.Combine( Common.PsToolsDir, "robocopy.exe" ); }
        }

        protected override void Simulate()
        {
            Common.RunCommand( Command, string.Format( "{0} /L", Args ), Progress );

            Progress.AddFormat( "Simulated copy from {0} to {1}", m_srcDir, m_destDir );
        }
    }
}
